package com.mock.dao.impl;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;

import com.mock.dao.GenericDao;
import com.mock.model.Organisation;
import com.mock.utils.HibernateUtil;

public class GenericDaoImpl<T, PK extends Serializable> implements GenericDao<T, PK> {
	

	@Override
	public T add(T newInstance) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();
		session.saveOrUpdate(newInstance);
		session.flush();
		session.getTransaction().commit();
		return newInstance;
	}


	@SuppressWarnings("unchecked")
	@Override
	public T getById(Class<T> T, PK id) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();
		T object = null;
		object = (T) session.get(T, id);
		session.flush();
		session.getTransaction().commit();
		return object;
	}

	@Override
	public T update(T transientObject) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();
		session.saveOrUpdate(transientObject);
		session.flush();
		session.getTransaction().commit();
		return transientObject;
	}

	@Override
	public void delete(T persistentObject) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();
		session.delete(persistentObject);
		session.flush();
		session.getTransaction().commit();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> getAll(Class<T> T) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();
		List<T> list = session.createQuery("from " + T.getName()).list();
		session.flush();
		session.getTransaction().commit();
		return list;
	}


	@Override
	public int getRowCount(Class<T> T) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();
		int count = ((Long) session.createQuery(
				"select count(*) from " + T.getName()).uniqueResult()).intValue();
		session.flush();
		session.getTransaction().commit();
		return count;
	}

	@SuppressWarnings("unchecked")
	@Override
	public T getByColumn(Class<T> T, String nameColume, String valueSearch) {
		
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();
		Query query = session.createQuery("from " + T.getName() + " where " + nameColume + "=:valueSearch");
		query.setParameter("valueSearch", valueSearch);
		T object = (T)query.uniqueResult();
		session.flush();
		session.getTransaction().commit();
		return object;
	}


	@SuppressWarnings("unchecked")
	@Override
	public List<T> getListByColumn(Class<T> T, String columnName, String valueSearch) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.getTransaction().begin();
		Query query = session.createQuery("from " + T.getName() + " where " + columnName + "=:valueSearch");
		query.setParameter("valueSearch", valueSearch);
		List<T> object = query.list();
		session.flush();
		session.getTransaction().commit();
		return object;
	}

	@Override
	public List<Long> getOrganisationDetailsTwoByOrganisation(Organisation organisation, Class<T> T, String alias) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();
		Criteria c = session.createCriteria(T, "t");

		DetachedCriteria dc = DetachedCriteria.forClass(Organisation.class, "o");
		dc.createAlias("o." + alias, alias);
		dc.add(Restrictions.eq("o.organisationId", organisation.getOrganisationId()));
		dc.setProjection(Projections.property(alias + ".id"));

		c.add(Subqueries.propertyIn("t.id", dc));	
		c.setProjection(Projections.property("id"));
		List<Long> list = c.list();			
		session.getTransaction().commit();
	    return list;
	}
}
